package com.homelock.service;

import java.util.*;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSONObject;
import com.homelock.common.constants.Connectors;
import com.homelock.common.enums.ServiceTypeEnum;
import com.homelock.common.enums.TriggerTypeEnum;
import com.homelock.common.enums.ZxTriggerTypeEnum;
import com.homelock.common.enums.sms.SmsSendTypeEnum;
import com.homelock.constants.OpmodeEnum;
import com.homelock.constants.UnlockAttributeEnum;
import com.homelock.constants.ZxUserTypeEnum;
import com.homelock.dto.HlOpenDoorRecordDto;
import com.homelock.dto.HuaWeiIotRecord;
import com.homelock.entity.*;
import com.homelock.thread.AlarmSmsAsyncTask;
import com.pi.base.enumerate.record.RecordState;
import com.pi.base.exception.ServiceException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import com.homelock.domain.query.OpenRecordQuery;
import com.homelock.entity.HlOpenDoorRecordExample.Criteria;
import com.homelock.mapper.HlOpenDoorRecordMapper;
import com.homelock.vo.OpenDoorRecordVO;
import com.pi.base.util.time.DateTools;

@Service
public class LockOpenRecordService {
    private static final Logger logger = LoggerFactory.getLogger(LockOpenRecordService.class);

    @Autowired
    private HlOpenDoorRecordMapper hlOpenDoorRecordMapper;
    @Autowired
    private LockUserService lockUserService;
    @Autowired
    private HlDevInfoService hlDevInfoService;
    @Autowired
    private AlarmSmsAsyncTask alarmSmsAsyncTask;
    @Autowired
    private HlDevUserUnlockService hlDevUserUnlockService;
    @Autowired
    private HlFamilyLinkageService hlFamilyLinkageService;

    public List<OpenDoorRecordVO> queryOpenRecordList(OpenRecordQuery openRecordQuery) {
        HlOpenDoorRecordExample example = new HlOpenDoorRecordExample();
        Criteria criteria = example.createCriteria();
        List<HlDevUser> userLockList = lockUserService.queryUserLockList(openRecordQuery.getOperateUserId());
        if (CollectionUtils.isEmpty(userLockList)) {
            return new ArrayList<OpenDoorRecordVO>(0);
        }
        Map<Long, HlDevUser> devUserMap = userLockList.stream().collect(Collectors.toMap(HlDevUser::getDevId, devUser -> devUser));
        if (null != openRecordQuery.getDevId()) {
            if (!devUserMap.containsKey(openRecordQuery.getDevId())) {
                return new ArrayList<OpenDoorRecordVO>(0);
            }
            criteria.andDevIdEqualTo(openRecordQuery.getDevId());
        } else {
            criteria.andDevIdIn(new ArrayList<>(devUserMap.keySet()));
        }
        if (null != openRecordQuery.getUserId()) {
            criteria.andTriggerSourceIdEqualTo(openRecordQuery.getUserId());
        }
        if (null != openRecordQuery.getOpmode()) {
            criteria.andTriggerTypeEqualTo(openRecordQuery.getOpmode());
        }
        if (null != openRecordQuery.getRecordType()) {
            criteria.andRecordTypeEqualTo(openRecordQuery.getRecordType().byteValue());
        }
        criteria.andStateEqualTo(RecordState.STATE_NORMAL.getState());

        if (null != openRecordQuery.getLimit() && null != openRecordQuery.getOffset()) {
            example.setOrderByClause(" create_date DESC LIMIT " + openRecordQuery.getOffset() + " , " + openRecordQuery.getLimit());
        } else {
            example.setOrderByClause(" create_date DESC ");
        }
        List<HlOpenDoorRecord> list = hlOpenDoorRecordMapper.selectByExample(example);
        if (!CollectionUtils.isEmpty(list)) {
            // 设备名称
            List<HlDevInfo> devInfoList = hlDevInfoService.getDevInfoByIds(new ArrayList<>(devUserMap.keySet()));
            Map<Long, String> devNameMap = devInfoList.stream().collect(Collectors.toMap(HlDevInfo::getId, HlDevInfo::getDevName));
            List<OpenDoorRecordVO> voList = new ArrayList<>();
            for (HlOpenDoorRecord record : list) {
                OpenDoorRecordVO vo = new OpenDoorRecordVO();
                vo.setDevName(devNameMap.get(record.getDevId()) == null ? "" : devNameMap.get(record.getDevId()));
                vo.setOpmode(record.getTriggerType() + "");
                vo.setOpTime(DateTools.getFullDate(record.getCreateDate()));
                vo.setStatus("2");
                // 查询当前开门用户信息
                HlDevUserUnlock unlockInfo = hlDevUserUnlockService.queryById(record.getTriggerUnlockId());
                if (record.getTriggerSourceId() != null && record.getTriggerSourceId() != 0L) {
                    if (unlockInfo != null) {
                        vo.setUserName(unlockInfo.getUnlockName());
                    }
                    vo.setOpenName(queryUserName(record));
                } else {
                    if (unlockInfo != null) {
                        vo.setUserName(unlockInfo.getUnlockName());
                    }
                    vo.setOpenName(record.getTriggerName());
                }
                vo.setTriggerName(record.getTriggerName());
                voList.add(vo);
            }
            return voList;
        }
        return new ArrayList<>(0);
    }

    /**
     * 查询振兴锁的开门记录
     * 没有用户概念 只有某个门锁的开门记录列表
     *
     * @param openRecordQuery
     * @return
     */
    public List<OpenDoorRecordVO> queryZxOpenRecordList(OpenRecordQuery openRecordQuery) {
        List<HlDevUser> userLockList = lockUserService.queryUserLockList(openRecordQuery.getOperateUserId());
        if (CollectionUtils.isEmpty(userLockList)) {
            return new ArrayList<OpenDoorRecordVO>(0);
        }
        HlOpenDoorRecordExample example = new HlOpenDoorRecordExample();
        Criteria criteria = example.createCriteria();
        Map<Long, HlDevUser> devUserMap = userLockList.stream().collect(Collectors.toMap(HlDevUser::getDevId, devUser -> devUser));
        if (null != openRecordQuery.getDevId()) {
            if (!devUserMap.containsKey(openRecordQuery.getDevId())) {
                return new ArrayList<OpenDoorRecordVO>(0);
            }
            criteria.andDevIdEqualTo(openRecordQuery.getDevId());
        } else {
            criteria.andDevIdIn(new ArrayList<>(devUserMap.keySet()));
        }
        if (null != openRecordQuery.getOpmode()) {
            criteria.andTriggerTypeEqualTo(openRecordQuery.getOpmode());
        }
        if (null != openRecordQuery.getRecordType()) {
            criteria.andRecordTypeEqualTo(openRecordQuery.getRecordType().byteValue());
        }
        criteria.andStateEqualTo(RecordState.STATE_NORMAL.getState());

        if (null != openRecordQuery.getLimit() && null != openRecordQuery.getOffset()) {
            example.setOrderByClause(" id DESC LIMIT " + openRecordQuery.getOffset() + " , " + openRecordQuery.getLimit());
        } else {
            example.setOrderByClause(" id DESC ");
        }
        List<HlOpenDoorRecord> list = hlOpenDoorRecordMapper.selectByExample(example);
        if (!CollectionUtils.isEmpty(list)) {
            List<HlDevInfo> devInfoList = hlDevInfoService.getDevInfoByIds(new ArrayList<>(devUserMap.keySet()));
            Map<Long, String> devNameMap = devInfoList.stream().collect(Collectors.toMap(HlDevInfo::getId, HlDevInfo::getDevName));

            // HlDevInfo hlDevInfo = hlDevInfoService.getDevInfobyId(openRecordQuery.getDevId());
            List<OpenDoorRecordVO> voList = new ArrayList<>();
            for (HlOpenDoorRecord record : list) {
                OpenDoorRecordVO vo = new OpenDoorRecordVO();
                vo.setDevName(Optional.ofNullable(devNameMap.get(record.getDevId())).orElse(""));
                vo.setOpmode(record.getTriggerType() + "");
                vo.setOpTime(DateTools.getFullDate(record.getCreateDate()));
                vo.setStatus("2");
                // 查询当前开门用户信息
                if (record.getTriggerId() != null && record.getTriggerId() != 0L) {
                    // 查询振兴锁可能涉及到修改的名称
                    //HlDevUserUnlock unlock = hlDevUserUnlockService.queryById(record.getTriggerSourceId());
                    HlDevUserUnlock unlock = hlDevUserUnlockService.findOneByDevIdAnUnlockIdAndStatusTrue(record.getDevId(),
                            record.getTriggerId() + "");
                    Optional<HlDevUserUnlock> unlockOption = Optional.ofNullable(unlock);
                    vo.setUserName(unlockOption.map(HlDevUserUnlock::getUnlockName).orElse(StringUtils.EMPTY));
                    vo.setOpenName(unlockOption.map(HlDevUserUnlock::getUnlockName).filter(o -> !o.isEmpty())
                            .orElseGet(() -> (null == record.getTriggerId() || Objects.equals(record.getTriggerId(), 0L))
                                    ? ZxUserTypeEnum.UNDEFINED_USER.getDesc() :
                                    record.getTriggerId().toString()));
                    //  vo.setOpenName(Optional.ofNullable(unlock).map(HlDevUserUnlock::getUnlockName).orElse(ZxUserTypeEnum.UNDEFINED_USER.getDesc()));
                } else {
                    // 有一种情况是未知用户开门 sourceId=0
                    if (record.getRecordType() == ServiceTypeEnum.MESSAGE.getType().byteValue()) {
                        vo.setOpenName(ZxUserTypeEnum.UNDEFINED_USER.getDesc());
                    } else {
                        vo.setOpenName(record.getTriggerName());
                    }
                    HlDevUserUnlock unlock = hlDevUserUnlockService.findOneByDevIdAnUnlockIdAndStatusTrue(record.getDevId(),
                            record.getTriggerId() + "");
                    vo.setUserName(unlock.getUnlockName());
                    // 普通开门上传的就是id
                    //  vo.setOpenName(String.valueOf(record.getTriggerId()));
                }
                vo.setTriggerName(record.getTriggerName());
                voList.add(vo);
            }
            return voList;
        }
        return new ArrayList<>(0);
    }


    /**
     * 插入推送记录
     *
     * @param recordObject
     * @return
     */
    @Transactional
    public boolean insertLockOpenRecord(JSONObject recordObject) {
        // 验证对象
        HuaWeiIotRecord record = checkInsertRecord(recordObject);
        if (record == null || StringUtils.isEmpty(record.getNotifyType()) || "deviceDatasChanged".equals(record.getNotifyType())) {
            logger.error("NotifyType不匹配，忽略开门记录");
            return false;
        }
        // 构造本地存储数据对象,根据imei查询
        HlDevInfo hlDevInfo = hlDevInfoService.getDevInfoByImei(record.getImei());
        // 根据imei查询不到门锁 关联失败 存储失败
        if (hlDevInfo == null) {
            logInsertError("本地数据库查询不到该锁具[" + record.getImei() + "]信息", recordObject.toJSONString());
            return false;
        }
        // 查询到本地设备idhomelock-zx-1.0.0.jar
        Long devId = hlDevInfo.getId();
        // 数据转换
        List<HlOpenDoorRecord> recordList = HlOpenDoorRecordDto.convertRecord(record, devId);
        if (recordList.size() == 0) {
            logger.info("推送消息解析不出任何开门记录或者报警记录，存储0条记录");
            return false;
        }
        for (HlOpenDoorRecord item : recordList) {
            // 获取关联用户id 区分是普通开门还是报警开门
            item = fingerOrPwdOrCardRecord(item);
            item.setCommunityId(hlDevInfo.getCommunityId());
            item.setSourceId(hlDevInfo.getSourceId());
            hlOpenDoorRecordMapper.insertSelective(item);
            logger.info("一条记录存储成功：" + item.toString());
            sendAlarmSms(item, devId, hlDevInfo);
            sendFamilySms(item, devId, hlDevInfo);
        }
        return true;
    }

    private HlOpenDoorRecord fingerOrPwdOrCardRecord(HlOpenDoorRecord record) {
        if (StringUtils.isEmpty(record.getTriggerUserId())) {
            return record;
        }
        // 指纹开门check转换
        record = changeRecordEnitity(true, record, TriggerTypeEnum.FINGER_OPEN, OpmodeEnum.UNLOCK_FINGER.getOpmode(), TriggerTypeEnum.FINGER_ALARM);
        // 密码开门check转换
        record = changeRecordEnitity(true, record, TriggerTypeEnum.PWD_OPEN, OpmodeEnum.UNLOCK_PASSWPRD.getOpmode(), TriggerTypeEnum.PWD_ALARM);
        // 卡片开门check转换
        record = changeRecordEnitity(false, record, TriggerTypeEnum.CARD_OPEN, OpmodeEnum.UNLOCK_CARD.getOpmode(), null);
        // 蓝牙开门 sourceId即用户id
        if (record.getTriggerType() == TriggerTypeEnum.BLUETOOH_OPEN.getCode()) {
            Long sourceId = 0L;
            try {
                sourceId = Long.valueOf(record.getTriggerUserId());
            } catch (Exception e) {
            }
            record.setTriggerSourceId(sourceId);
        }
        return record;
    }


    /**
     * 查询当前密码/指纹/蓝牙等userId为非用户id，查询关联id
     * 同时根据关联id是否为报警类型
     *
     * @param record
     * @param equalTrigeerEnum
     * @param queryOpMode
     * @param setTriggerTypeEnum
     * @return
     */
    private HlOpenDoorRecord changeRecordEnitity(boolean checkAlarm, HlOpenDoorRecord record, TriggerTypeEnum equalTrigeerEnum, byte queryOpMode, TriggerTypeEnum setTriggerTypeEnum) {
        if (record.getTriggerType() == equalTrigeerEnum.getCode()) {
            // 查询当前设备指纹/密码/卡片信息
            HlDevUserUnlock userUnlock = hlDevUserUnlockService.queryByDevIdAndUnlockTypeAndUnlockId(record.getDevId(),
                    queryOpMode, record.getTriggerUserId());
            if (userUnlock == null) {
                return record;
            }
            record.setTriggerUnlockId(userUnlock.getId());
            if (record.getTriggerType() == TriggerTypeEnum.FINGER_OPEN.getCode()) {
                record.setTriggerSourceId(userUnlock.getDevUserId());
            } else {
                record.setTriggerSourceId(userUnlock.getId());
            }
            if (checkAlarm && userUnlock.getUnlockAttribute() == UnlockAttributeEnum.ALARM.getAttribute()) {
                // 指纹报警 需要更改当前记录类型
                record.setRecordType(ServiceTypeEnum.Alarm.getType().byteValue());
                record.setTriggerType(setTriggerTypeEnum.getCode());
                record.setTriggerName(setTriggerTypeEnum.getName());
            }
        }
        return record;
    }

    /**
     * 发送报警短信模块
     *
     * @param item
     * @param devId
     * @param hlDevInfo
     */
    public void sendAlarmSms(HlOpenDoorRecord item, Long devId, HlDevInfo hlDevInfo) {
        // check 报警类型
        if (null != hlDevInfo.getOwnerId() && (item.getTriggerType() == TriggerTypeEnum.RETRY_FORBIDDEN_ALARM.getCode()
                || item.getTriggerType() == TriggerTypeEnum.PICK_ALARM.getCode()
                || item.getTriggerType() == TriggerTypeEnum.FINGER_ALARM.getCode()
                || item.getTriggerType() == TriggerTypeEnum.PWD_ALARM.getCode())) {
            // 验证当前锁是否有注册人
            HlDevUser hlDevOwner = lockUserService.queryLockUserByDevIdAndUserId(devId, hlDevInfo.getOwnerId());
            // 当前锁具没有注册人 则无需发送短信
            if (hlDevOwner != null) {
                String openUserName = "";
                if (item.getTriggerType() == TriggerTypeEnum.FINGER_ALARM.getCode() && item.getTriggerSourceId() != 0L) {
                    // 指纹报警，查询当前触发对象
                    HlDevUser hlDevUser = lockUserService.queryByIdAndDevId(item.getTriggerSourceId(), devId);
                    openUserName = (hlDevUser == null) ? "" : hlDevUser.getDevUserName();
                }
                // 异步发送报警短信
                alarmSmsAsyncTask.runAlarmSmsAsyncTask(TriggerTypeEnum.val(item.getTriggerType()), hlDevInfo, openUserName);
            } else {
                logger.info("[SendAlarmSms]:该锁已经被清空，没有注册人，无需发送短信");
            }
        }
    }

    /**
     * 发送报警短信模块
     *
     * @param item
     * @param devId
     * @param hlDevInfo
     */
    public void sendZxSms(HlOpenDoorRecord item, Long devId, HlDevInfo hlDevInfo) {
        // check 报警类型
        SmsSendTypeEnum smsSendType = ZxTriggerTypeEnum.getSmsSendTypeByCode(item.getTriggerType());
        if (null == smsSendType) {
            logger.info("[dev_trigger_error] devId: {}, triggerId: {}", devId, item.getTriggerType());
            return;
        }
        String devAlarmSet = hlDevInfo.getDevAlamerset();
        if (StringUtils.isNotBlank(devAlarmSet)) {
            String[] alarmSet = devAlarmSet.split(Connectors.CONNECTOR_ALARM_SET);
            logger.info("[dev_alarm_set] devId: {}, alarmSet: {}",
                    hlDevInfo.getId(), hlDevInfo.getDevAlamerset());
            if (alarmSet.length == 2) {
                if (!Objects.equals("1", alarmSet[0]) && smsSendType == SmsSendTypeEnum.ALARM_HIJACK) {
                    return;
                }
                if (!Objects.equals("1", alarmSet[1]) && smsSendType == SmsSendTypeEnum.ALARM_LOCK_PICK) {
                    return;
                }
            }
        }
        // 验证当前锁是否有注册人
        HlDevUser hlDevOwner = lockUserService.queryLockUserByDevIdAndUserId(devId, hlDevInfo.getOwnerId());
        // 当前锁具没有注册人 则无需发送短信
        if (hlDevOwner != null) {
            String openUserName = "";
            if (SmsSendTypeEnum.ALARM_FINGER == smsSendType && item.getTriggerSourceId() != 0L) {
                // 指纹报警，查询当前触发对象
                HlDevUser hlDevUser = lockUserService.queryByIdAndDevId(item.getTriggerSourceId(), devId);
                openUserName = (hlDevUser == null) ? "" : hlDevUser.getDevUserName();
            }
            // 异步发送报警短信
            alarmSmsAsyncTask.runSmsSendByTypeTaskAsync(smsSendType, hlDevInfo, openUserName);
        } else {
            logger.info("[SendAlarmSms]:该锁已经被清空，没有注册人，无需发送短信");
        }
    }

    /**
     * 发送亲情短信模块
     * 蓝牙开门-有开门用户的微信id
     * 指纹开门-有开门用户的devUserId
     *
     * @param item
     * @param devId
     * @param hlDevInfo
     */
    private void sendFamilySms(HlOpenDoorRecord item, Long devId, HlDevInfo hlDevInfo) {
        // 蓝牙开门有开门用户，指纹开门有开门用户
        if (null != hlDevInfo.getOwnerId()
                && (item.getTriggerType() == TriggerTypeEnum.BLUETOOH_OPEN.getCode()
                || item.getTriggerType() == TriggerTypeEnum.FINGER_OPEN.getCode())) {
            HlDevUser sendUser;
            if (item.getTriggerType() == TriggerTypeEnum.BLUETOOH_OPEN.getCode()) {
                // 蓝牙开门
                sendUser = lockUserService.queryLockUserByDevIdAndUserId(devId, item.getTriggerSourceId());
            } else {
                // 指纹开门
                sendUser = lockUserService.queryByIdAndDevId(item.getTriggerSourceId(), devId);
            }
            if (sendUser == null) {
                logger.info("[SendFamilySms]:该开门记录查询不到蓝牙或者指纹对应的开门用户，无需发送亲情短信");
                return;
            }
            List<HlFamilyLinkage> receiverList = hlFamilyLinkageService.queryTargetUserByDevIdAndUserId(devId, sendUser.getId());
            if (CollectionUtils.isEmpty(receiverList)) {
                logger.info("[SendFamilySms]:该开门记录对应的开门用户无亲情关联，无需发送亲情短信");
                return;
            }
            // 异步发送亲情短信
            alarmSmsAsyncTask.runFamilySmsAsyncTask(hlDevInfo, sendUser, receiverList);

        }
    }

    /**
     * 开门记录：查询开门相关用户名称
     *
     * @return
     */
    private String queryUserName(HlOpenDoorRecord record) {
        if (record.getTriggerType() == TriggerTypeEnum.FINGER_OPEN.getCode() ||
                record.getTriggerType() == TriggerTypeEnum.FINGER_ALARM.getCode()) {
            // 指纹开锁 userId是devUser的id
            HlDevUser fingerUser = lockUserService.queryByIdAndDevId(record.getTriggerSourceId(), record.getDevId());
            if (fingerUser != null && !StringUtils.isEmpty(fingerUser.getDevUserName())) {
                return new StringBuffer("").append(fingerUser.getDevUserName())
                        .append("的").append(record.getTriggerName()).toString();
            }
            return record.getTriggerName();
        } else if (record.getTriggerType() == TriggerTypeEnum.BLUETOOH_OPEN.getCode()) {
            // 蓝牙的用户是wechat userId
            HlDevUser openUser = lockUserService.queryLockUserByDevIdAndUserId(record.getDevId(), record.getTriggerSourceId());
            if (openUser != null) {
                return new StringBuffer("").append(openUser.getDevUserName()).append("的").append(record.getTriggerName()).toString();
            }
            return record.getTriggerName();
        }
        // 门卡 密码开锁
        HlDevUserUnlock hlDevUserUnlock = hlDevUserUnlockService.queryById(record.getTriggerSourceId());
        if (hlDevUserUnlock != null && !StringUtils.isEmpty(hlDevUserUnlock.getUnlockName())) {
            return new StringBuffer("").append(hlDevUserUnlock.getUnlockName()).append("开锁").toString();
        }
        return record.getTriggerName();
    }

    /**
     * check推送对象
     *
     * @param jsonObject
     * @return
     */
    private HuaWeiIotRecord checkInsertRecord(JSONObject jsonObject) {
        Assert.notNull(jsonObject, "推送对象为空");
        HuaWeiIotRecord record = JSONObject.parseObject(jsonObject.toJSONString(), HuaWeiIotRecord.class);
        // jsonObject.toJavaObject(HuaWeiIotRecord.class);
        String checkMsg = record.checkValidate();
        if (checkMsg.length() > 0) {
            logInsertError(checkMsg, jsonObject.toJSONString());
            throw new ServiceException(checkMsg);
        }
        return record;
    }

    private void logInsertError(String errorMsg, String object) {
        logger.error("[推送数据存储失败][err:{}][data:{}]", errorMsg, object);
    }

    public void clearByDevId(Long devId) {
        // TODO Auto-generated method stub
        HlOpenDoorRecordExample example = new HlOpenDoorRecordExample();
        example.createCriteria().andDevIdEqualTo(devId).andStateEqualTo(RecordState.STATE_NORMAL.getState());
        HlOpenDoorRecord record = new HlOpenDoorRecord();
        record.setState(RecordState.STATE_DELETE.getState());
        hlOpenDoorRecordMapper.updateByExampleSelective(record, example);
    }

    /**
     * 新增振兴锁的开门记录
     *
     * @param record
     */
    public void insertZxLock(HlOpenDoorRecord record) {
        Date date = new Date();
        record.setCreateDate(date);
        record.setUpdateDate(date);
        record.setState(RecordState.STATE_NORMAL.getState());
        record.setVersion(1L);
        hlOpenDoorRecordMapper.insertSelective(record);
    }
}
